#!/usr/bin/python
# @Time  : 2020/9/17 16:43
# @Author: LOUIE
# @Desc  : 程序执行入口
from config import CASE_DIR
from utils import loader
from utils.logger import log
from utils.const import variables_pool
from utils.dingtalk import DingTalk
from utils.tools import parse_summary, send_email
from XTestRunner import HTMLTestRunner
from core.api import run_test
from core.context import Context
import unittest
import config
import os
import datetime


class Runner:

    def __init__(self):
        self.test_loader = unittest.TestLoader()
        self.context = Context(variables_pool())
        self.dingtalk = DingTalk(config.WEBHOOK)

    def _add_tests(self, testcases):
        def _add_step(config, variable, test_dict):
            def test(self):
                try:
                    run_test(config, variable, test_dict)
                except Exception as ex:
                    self.fail(str(ex))
            return test

        test_suite = unittest.TestSuite()

        for testcase in testcases:

            config = testcase.get("config", {})
            case_desc = config.get('case_desc', 'no description')
            export = config.get('export', {})
            self.context.update_test_variables(loader.load_env_variables(config))
            variable = self.context.test_variables_pool
            # env_variable = loader.load_env_variables(config)
            # variable = variables_pool()
            # variable.update(env_variable)

            teststeps = testcase.get("steps", [])

            # 使用type生成测试用例类
            TestSequense = type(config.get('case_name', 'TestSequense'), (unittest.TestCase,), {})
            # 添加类注释，可以在报告中展示明细
            TestSequense.__doc__ = case_desc

            # 分解成用例类中的用例方法
            for index, tests_dict in enumerate(teststeps):
                test_func_name = 'test_{:04}'.format(index)
                test_func = _add_step(config, variable, tests_dict)
                test_desc = tests_dict.get('name', test_func_name)
                setattr(TestSequense, test_func_name, test_func)
                func = getattr(TestSequense, test_func_name)
                func.__doc__ = test_desc

            # 收集测试用例，添加进测试套件
            loaded_testcase = self.test_loader.loadTestsFromTestCase(TestSequense)
            test_suite.addTest(loaded_testcase)

        return test_suite

    def _run_suite(self, test_suite):
        """
        运行测试套件
        :param test_suite:
        :return:
        """

        filename = str(datetime.datetime.now().strftime("%Y-%m-%d %H-%M-%S")) + '.html'
        filepath = os.path.join(config.REPORT_DIR, filename)
        with open(filepath, 'wb+') as fp:
            runner = HTMLTestRunner(
                stream=fp,
                title='（AutoTest-Mall） Test Report',
                description='describe: AutoTest-Mall',
                language='zh-CN',
                tester='LOUIE'
            )
            result = runner.run(
                testlist=test_suite,
                rerun=1,
                save_last_run=False
            )
        log.info(f'Generating HTML reports... filepath: {filepath}')

        # 发送邮件
        # send_email(filepath)

        attr = runner.get_report_attributes(result)
        return attr

    def run(self, *file_or_dir, **kwargs):
        """
        运行程序函数
        :param file_or_dir:
        :param kwargs:
        :return:
        """
        log.info(" = " * 8 + " Program started, Running tests  " + " = " * 8)
        if "env" in kwargs.keys():
            config.ENV = kwargs.get("env").lower()
        if file_or_dir:
            file_list = [(os.path.join(CASE_DIR, filename)) for filename in file_or_dir]
        else:
            file_list = loader.load_folder(CASE_DIR)
        testcases = []
        for filepath in file_list:
            test_dict = loader.load_yaml(filepath=filepath)
            testcase_name = test_dict.get("config").get("case_desc")
            log.info("Start to collect testcase: {}".format(testcase_name))
            testcases.append(test_dict)
        test_suite = self._add_tests(testcases=testcases)
        result = self._run_suite(test_suite)
        result = parse_summary(result)
        self.dingtalk.send_message_to_ding(result, at_mobiles=[15338807445])
        log.info(" = " * 8 + " Program finished, Testing is completed " + " = " * 8)


if __name__ == '__main__':
    Runner().run()
    # Runner().run(['shopping_cart.yaml', 'shopping.yaml',
    #               'set_default_address.yaml', 'address.yaml',
    #               'home_page_api.yaml', 'modify_personal_info.yaml',
    #               'order_statistics.yaml', 'product_category.yaml',
    #               ], "prod")

